package com.mars.component.scheduler.quartz;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mars.component.scheduler.enums.SchedulerConst;
import com.mars.component.scheduler.exception.SchedulerJobException;
import com.mars.component.scheduler.model.SchedulerJob;
import com.mars.component.scheduler.spring.ScheduleJobQuartz;

/**
 * Scheduler工具类
 * @类名 SchedulerUtils
 * @日期 2016年12月29日 上午9:05:36
 * @作者 yhaoquan
 * @版权 (c) All Rights Reserved, 2016.
 */
@Component
public class SchedulerUtils {
	
	private static Logger logger = LoggerFactory.getLogger(SchedulerUtils.class) ;
	
	@Autowired
	private Scheduler scheduler ;
	
	
	/**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(String jobId, String group) {
    	if(null != group) {
    		return TriggerKey.triggerKey(jobId, group) ;
    	} else {
    		return TriggerKey.triggerKey(jobId);
    	}
    }
    
    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(String jobId, String group) {
    	if(null != group) {
    		return JobKey.jobKey(jobId, group);
    	} else {
    		return JobKey.jobKey(jobId);
    	}
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId, String group) throws SchedulerException {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId, group));
        } catch (SchedulerException e) {
        	logger.error("获取表达式触发器：" + e);
			throw e ;
        }
    }
    
    /**
     * 创建定时任务
     * @param clazz 任务执行类，该类需实现Job接口
     * @param schedulerJob 任务信息对象 
     * @throws SchedulerException
     */
    public void createScheduleJob(Class<? extends Job> clazz, SchedulerJob schedulerJob) throws SchedulerException {
    	
    	//任务是否存在
    	if(this.checkExists(schedulerJob)) {
    		logger.warn("定时任务已存在，任务名称：{}，任务描述：{}", schedulerJob.getJobName(), schedulerJob.getDescription());
    	} else {
    		try {
    			//1: 构建Job信息，运行的类需要实现Job接口
    			JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup())).withDescription(schedulerJob.getDescription()).build();
    			
    			//设置参数
    			if(null != schedulerJob.getParams() && !schedulerJob.getParams().isEmpty()) {
    				jobDetail.getJobDataMap().putAll(schedulerJob.getParams());
    			}
    			
    			//2: 表达式调度构建器
    			CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(schedulerJob.getCronExpression()) ;
    			
    			//3: 按新的cronExpression表达式构建一个新的trigger
    			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(schedulerJob.getJobId(), schedulerJob.getJobGroup())).withSchedule(cronSchedule).build() ;
    			
    			//4: 创建任务调度
    			this.scheduler.scheduleJob(jobDetail, trigger) ;
    			
    			//设置任务状态
    			if(null != schedulerJob.getStatus() && schedulerJob.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
    				pauseJob(schedulerJob);
    			}
    			
    			logger.info("任务创建成功【任务状态：{}   任务ID： {}   任务类：{}   任务触发表达式：{}   任务描述：{}】", 
    					SchedulerConst.ScheduleStatus.getEnum(schedulerJob.getStatus()).getDesc(),
    					jobDetail.getKey(),
    					jobDetail.getJobClass(),
    					schedulerJob.getCronExpression(),
    					jobDetail.getDescription());
    		} catch (SchedulerException e) {
    			throw SchedulerJobException.CREATE_SCHEDULER_FAILED.logError(e) ;
    		}
    	}
    }
    
    /**
     * 通过Spring使用反射来执行任务类
     * <br>任务作业类 ScheduleJobQuartz 实现了Spring提供的QuartzJobBean抽象类
     * @param schedulerJob 任务信息对象 
     * @throws SchedulerException
     */
	public void createScheduleJob(SchedulerJob schedulerJob) throws SchedulerException {
		
		//任务是否存在
		if(this.checkExists(schedulerJob)) {
			logger.warn("定时任务已存在，任务名称：{}，任务描述：{}", schedulerJob.getJobName(), schedulerJob.getDescription());
			
		} else {
			try {
				//1: 构建Job信息，运行的类需要实现Job接口
				JobDetail jobDetail = JobBuilder.newJob(ScheduleJobQuartz.class).withIdentity(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup())).withDescription(schedulerJob.getDescription()).build();
				
				//把当前任务作业类存放入jobDetail的Map参数中
				jobDetail.getJobDataMap().put(SchedulerJob.JOB_PARAM_KEY, schedulerJob);
				
				//2: 表达式调度构建器
				CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(schedulerJob.getCronExpression()) ;
				
				//3: 按新的cronExpression表达式构建一个新的trigger
				CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(schedulerJob.getJobId(), schedulerJob.getJobGroup())).withSchedule(cronSchedule).build() ;
				
				//4: 创建任务调度
				this.scheduler.scheduleJob(jobDetail, trigger) ;
				
				//设置任务状态
				if(null != schedulerJob.getStatus() && schedulerJob.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
					pauseJob(schedulerJob);
				}
				
				logger.info("任务创建成功【任务状态：{}   任务ID： {}   任务类：{}   任务触发表达式：{}   任务描述：{}】", 
						SchedulerConst.ScheduleStatus.getEnum(schedulerJob.getStatus()).getDesc(),
						jobDetail.getKey(),
						jobDetail.getJobClass(),
						schedulerJob.getCronExpression(),
						jobDetail.getDescription());
			} catch (SchedulerException e) {
				throw SchedulerJobException.CREATE_SCHEDULER_FAILED.logError(e) ;
			}
		}
	}
	
	/**
	 * 修改任务调度的触发时间
	 * @param schedulerJob
	 */
	public void rescheduleJob(SchedulerJob schedulerJob) throws SchedulerException {
		try {
            TriggerKey triggerKey = getTriggerKey(schedulerJob.getJobId(), schedulerJob.getJobGroup());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(schedulerJob.getCronExpression());

            CronTrigger trigger = getCronTrigger(scheduler, schedulerJob.getJobId(), schedulerJob.getJobGroup());
            
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            
            scheduler.rescheduleJob(triggerKey, trigger);
            
            //设置任务状态
            if(null != schedulerJob.getStatus() && schedulerJob.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
				pauseJob(schedulerJob);
			}
            
        } catch (SchedulerException e) {
        	throw SchedulerJobException.RESCHEDULER_JOB_EXCEPTION.logError(e) ;
        }
	}
	
	/**
	 * 暂停任务调度
	 * @param schedulerJob
	 */
	public void pauseJob(SchedulerJob schedulerJob) throws SchedulerException {
		try {
			scheduler.pauseJob(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup()));
		} catch (SchedulerException e) {
			throw SchedulerJobException.PAUSE_JOB_EXCEPTION.logError(e) ;
		}
	}
	public void pauseJob(String jobId, String jobGroup) throws SchedulerException {
		try {
            scheduler.pauseJob(getJobKey(jobId, jobGroup));
        } catch (SchedulerException e) {
        	throw SchedulerJobException.PAUSE_JOB_EXCEPTION.logError(e) ;
        }
	}
	
	/**
	 * 恢复任务调度
	 * @param schedulerJob
	 */
	public void resumeJob(SchedulerJob schedulerJob) throws SchedulerException {
		try {
			scheduler.resumeJob(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup()));
		} catch (SchedulerException e) {
			throw SchedulerJobException.RESUME_EXCEPTION.logError(e) ;
		}
	}
	public void resumeJob(String jobId, String jobGroup) throws SchedulerException {
		try {
            scheduler.resumeJob(getJobKey(jobId, jobGroup));
        } catch (SchedulerException e) {
        	throw SchedulerJobException.RESUME_EXCEPTION.logError(e) ;
        }
	}
	
	/**
	 * 删除任务
	 * @param schedulerJob
	 */
	public void deleteJob(SchedulerJob schedulerJob) throws SchedulerException {
		try {
			scheduler.deleteJob(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup()));
		} catch (SchedulerException e) {
			throw SchedulerJobException.DELETE_JOB_EXCEPTION.logError(e) ;
		}
	}
	public void deleteJob(String jobId, String jobGroup) throws SchedulerException {
		try {
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        } catch (SchedulerException e) {
        	throw SchedulerJobException.DELETE_JOB_EXCEPTION.logError(e) ;
        }
	}
	
	/**
     * 立即执行任务
     */
	public void runNow(SchedulerJob schedulerJob) throws SchedulerException {
		try {
			scheduler.triggerJob(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup()));
		} catch (SchedulerException e) {
			throw SchedulerJobException.RUN_SCHEDULER_FAILED.logError(e) ;
		}
	}
	public void runNow(String jobId, String jobGroup) throws SchedulerException {
		try {
			scheduler.triggerJob(getJobKey(jobId, jobGroup));
		} catch (SchedulerException e) {
			throw SchedulerJobException.RUN_SCHEDULER_FAILED.logError(e) ;
		}
	}
	
	/**
	 * 任务是否存在（true：存在，false：不存在）
	 * @param jobId
	 * @param jobGroup
	 * @return boolean
	 */
	public boolean checkExists(SchedulerJob schedulerJob) {
		try {
			return scheduler.checkExists(getJobKey(schedulerJob.getJobId(), schedulerJob.getJobGroup())) ;
		} catch (SchedulerException e) {
			throw SchedulerJobException.SCHEDULER_ALREADY_EXCEPTION.logError(e) ;
		}
	}
	public boolean checkExists(String jobId, String jobGroup) {
		try {
			return scheduler.checkExists(getJobKey(jobId, jobGroup)) ;
		} catch (SchedulerException e) {
			throw SchedulerJobException.SCHEDULER_ALREADY_EXCEPTION.logError(e) ;
		}
	}
	
}
